#include "table.h"
#include "messages.h"

#if defined(GENERIC)
ostream & Table::Print(ostream &os) const
{
  // WRITE THIS
  os << "Table()";
  return os;
}
#endif

#if defined(LINKSTATE)
int TopologyTable::updateLink(const Link *l){
	updated = true;
	int currentAge = m[l->GetSrc()][l->GetDest()].age;
	m[l->GetSrc()][l->GetDest()].age = ++currentAge;
	m[l->GetSrc()][l->GetDest()].cost = l->GetLatency();
	m[l->GetSrc()][l->GetDest()].distance = l->GetLatency();


	return currentAge;
}
bool TopologyTable::updateTable(const RoutingMessage * message){
	updated = true;
	if(m[message->src][message->dest].cost == -1){
		m[message->src][message->dest].cost = message->cost;
		m[message->src][message->dest].age = message->age;

		return true;
	}
	if(m[message->src][message->dest].age < message->age){
		m[message->src][message->dest].cost = message->cost;
		m[message->src][message->dest].age = message->age;

		return true;
	}

	return false;
}
void TopologyTable::printTable()
{
  // WRITE THIS
	cout << "PRINTING TABLEE!!!!" << endl;
  map<int, map<int,TopoLink> >::const_iterator itr;
	 for(itr=m.begin(); itr != m.end(); ++itr){
		 cout<< "----------------------------" << endl;
		 	 cout <<(itr)->first << ": ";
		 	map<int, TopoLink >::const_iterator itr2;
		 	 for(itr2=(itr)->second.begin(); itr2 != (itr)->second.end(); ++itr2){
			 	 cout <<(itr2)->first << "( " << (itr2)->second.cost << "),";
		 	 }
		 	 cout << endl;
		}

}
void TopologyTable::find(int *src, int *dest){
	  int maxCost = -1;
	  map<int, map<int,TopoLink> >::const_iterator itr;
		 for(itr=m.begin(); itr != m.end(); ++itr){
			 	map<int, TopoLink >::const_iterator itr2;
			 	 for(itr2=(itr)->second.begin(); itr2 != (itr)->second.end(); ++itr2){
					 if(itr2->second.inSet && !itr2->second.used){
						 if(maxCost < 0){
							 *src = itr->first;
							 *dest = itr2->first;
							  maxCost = itr2->second.distance;
						 }
						 else if(maxCost <  itr2->second.distance){
							 *src = itr->first;
							 *dest = itr2->first;
							  maxCost = itr2->second.distance;
						 }
					 }
			 	 }
			}
}
#endif

#if defined(DISTANCEVECTOR)

bool Table::updateTable(const RoutingMessage * message){
	//map<int,int> bestHops = message->bestHops; // shortest
	//map<int,double> costs = message->costs; // shortestCost
	map<int,BestHop> shortest = message->shortest; // shortest
	unsigned src = message->src;

	// update big map
	map<int, map<int,double> >::const_iterator itr;
	for(itr=dist.begin(); itr != dist.end(); ++itr){

		//TODO: Check to make sure that this exists first.
		double prevCost = 0;
		if(shortest[(itr)->first].cost==-1)
			prevCost = 0;
		(itr)->second[src] = prevCost+dist[src][(itr)->first];
	}

	// see if better costs
	bool madeChange = false;
	map<int, map<int,double> >::const_iterator itr2;
	for(itr2=dist.begin(); itr2 != dist.end(); ++itr2){
		map<int,double>::const_iterator itr3;
		unsigned hop;
		double best =-1;
		for(itr3=dist[(itr2->first)].begin(); itr3 != dist[(itr2)->first].end(); ++itr3){
			if(best==-1){
				best = (itr3)->second;
				hop = itr3->first;
			}
			else if(itr3->second<best){
				best = (itr3)->second;
				hop = itr3->first;
			}
		}
		//TODO: Make sure it exists..
		double oldCost = shortest[itr->first].cost;
		if(oldCost!=-1 && best<oldCost){
			madeChange = true;
		}
		else{
			shortest[itr->first].cost = best;
			shortest[itr->first].hop = hop;
		}
	}

	return madeChange;
}

bool Table::updateLink(const Link *l){
	double newCost = l->GetLatency();
	int src = l->GetSrc();
	int dest = l->GetDest();

	// update distance map
	double difference = dist[dest][src] - newCost;
	map<int, map<int,double> >::const_iterator itr;
	 for(itr=dist.begin(); itr != dist.end(); ++itr){
			map<int, double >::const_iterator itr2;
			 for(itr2=(itr)->second.begin(); itr2 != (itr)->second.end(); ++itr2){
				 if((itr2)->first==dest)
					 dist[(itr)->first][(itr2)->first] += difference;
			 }
		}


	// find shortest path and update shortest map if necessary
	bool foundBetter = false;
	 map<int,double>::const_iterator itr1;
	 for(itr1=dist[dest].begin(); itr1 != dist[dest].end(); ++itr1){
		 //If destination doesn't exist, then put the value in it.
		 if(shortest[dest].cost==-1){
			 foundBetter = true;
			 shortest[dest].hop = (itr1)->first;
			 shortest[dest].cost = (itr1)->second;
		 }
		 //If the destination already input is greater than what we have, change it.
		 else if((itr1)->second< shortest[dest].cost){
			 foundBetter = true;
			 shortest[dest].hop = (itr1)->first;
			 shortest[dest].cost = (itr1)->second;
		 }
	 }

	 return foundBetter;
}

void Table::printFull()
{
  // WRITE THIS
	cout << "Full" << endl;
  map<int, map<int,double> >::const_iterator itr;
	 for(itr=dist.begin(); itr != dist.end(); ++itr){
		 cout<< "----------------------------" << endl;
		 	 cout <<(itr)->first << ": ";
		 	map<int, double >::const_iterator itr2;
		 	 for(itr2=(itr)->second.begin(); itr2 != (itr)->second.end(); ++itr2){
			 	 cout <<(itr2)->first << "( " << (itr2)->second << "),";
		 	 }
		 	 cout << endl;
		}

}

void Table::printShortest()
{
  // WRITE THIS
	cout << "Shortest" << endl;
  map<int, BestHop>::const_iterator itr;
	 for(itr=shortest.begin(); itr != shortest.end(); ++itr){
		 cout<< "----------------------------" << endl;
		 	 cout <<(itr)->first << ": Cost: "<<(itr)->second.cost << ": Hop: " << (itr)->second.hop;
		 	 cout << endl;
		}

}
#endif
